home *** CD-ROM | disk | FTP | other *** search
- /* resample.c
- vi:ts=3 sw=3:
- */
-
- /* $Id: resample.c,v 4.12 1995/02/14 04:02:28 espie Exp $
- * $Log: resample.c,v $
- * Revision 4.12 1995/02/14 04:02:28 espie
- * Nothing.
- *
- * Revision 4.12 1995/02/14 04:02:28 espie
- * Nothing.
- *
- * Revision 4.11 1995/02/06 14:50:47 espie
- * Changed sample_info.
- *
- * Revision 4.11 1995/02/06 14:50:47 espie
- * Changed sample_info.
- *
- * Revision 4.10 1995/02/01 17:14:54 espie
- * Scaled volume.
- *
- * Revision 4.10 1995/02/01 17:14:54 espie
- * Scaled volume.
- *
- * Revision 4.9 1995/02/01 16:39:04 espie
- * Implemented Left/Right channels, 23 bits output.
- *
- * Revision 4.8 1995/02/01 16:30:36 espie
- * *** empty log message ***
- *
- * Revision 4.7 1995/02/01 15:31:25 espie
- * *** empty log message ***
- *
- * Revision 4.6 1995/01/28 09:23:59 espie
- * *** empty log message ***
- *
- * Revision 4.5 1994/11/15 16:11:01 espie
- * *** empty log message ***
- *
- * Revision 4.5 1994/11/15 16:11:01 espie
- * *** empty log message ***
- *
- * Revision 4.4 1994/08/23 18:19:46 espie
- * New sampling function.
- * Finally corrected irksome probleme with MAX_PITCH.
- * First changes to augment the number of channels.
- * Added one level of abstraction. Look through player.c for the
- * old high-level functions.
- * Optimized output and fixed up some details.
- * Unrolled code for oversample = 1 to be more efficient at
- * higher frequency (since a high frequency is better than
- * a higher oversample).
- *
- * Revision 2.14 1992/11/06 19:31:53 espie
- * Fixed missing parameter type.
- * fix_xxx for better speed.
- * set_volume.
- * Added possibility to get back to MONO for the sgi.
- * Added stereo capabilities to the indigo version.
- * Minor bug: a SAMPLE_FAULT is a minor error,
- * we should first check that there was no other
- * error before setting it.
- * New resample function coming from the player.
- * Added more notes.
- *
- * Revision 2.1 1991/11/17 23:07:58 espie
- * Just computes some frequency-related parameters.
- *
- *
- */
-
- #include <math.h>
-
- #include "defs.h"
- #include "song.h"
- #include "channel.h"
- #include "tags.h"
- #include "extern.h"
-
- ID("$Id: resample.c,v 4.12 1995/02/14 04:02:28 espie Exp $")
-
- /* DO_NOTHING is also used for the automaton */
- #define DO_NOTHING 0
- #define PLAY 1
- #define REPLAY 2
-
- #define MAX_CHANNELS 8
-
- LOCAL struct audio_channel
- {
- struct sample_info *samp;
- int mode;
- unsigned long pointer;
- unsigned long step;
- int volume;
- int scaled_volume;
- int pitch;
- int side;
- } chan[MAX_CHANNELS];
-
- /* left/right */
- #define NUMBER_SIDES 2
- LOCAL int total[NUMBER_SIDES];
-
- LOCAL int allocated = 0;
-
- struct audio_channel *new_channel_tag_list(prop)
- struct tag *prop;
- {
- struct audio_channel *new;
-
- new = &chan[allocated++];
- new->mode = DO_NOTHING;
- new->pointer = 0;
- new->step = 0;
- new->pitch = 0;
- new->volume = 0;
- new->scaled_volume = 0;
- new->samp = empty_sample();
-
- while (prop = get_tag(prop))
- {
- switch(prop->type)
- {
- case AUDIO_SIDE:
- new->side = prop->data.scalar;
- break;
- default:
- break;
- }
- prop++;
- }
- total[new->side]++;
- return new;
- }
-
- void release_audio_channels()
- {
- allocated = 0;
- }
-
- /* Have to get some leeway for vibrato (since we don't bound pitch with
- * vibrato). This is conservative.
- */
- #define VIB_MAXDEPTH 150
-
-
- #define C fix_to_int(ch->pointer)
-
- LOCAL unsigned long step_table[REAL_MAX_PITCH + VIB_MAXDEPTH];
- /* holds the increment for finding the next sampled
- * byte at a given pitch (see resample() ).
- */
-
- /* creates a table for converting ``amiga'' pitch
- * to a step rate at a given resampling frequency.
- * For accuracy, we don't use floating point, but
- * instead fixed point ( << ACCURACY).
- * IMPORTANT NOTES:
- * - we need to make it fit within 32 bits (long), which
- * must be enough for ACCURACY + log2(max sample length)
- * - for the linear resampling to work correctly, we need
- * sample size (8 bit) + volume size (6 bit) + ACCURACY to fit within a
- * long. Appropriate steps will have to be taken when we switch to 16 bit
- * samples...
- * - never forget that samples are SIGNED numbers. If you have unsigned
- * samples, you have to convert them SOMEWHERE.
- */
-
- LOCAL void create_step_table(oversample, output_fr)
- int oversample; /* we sample oversample i for each byte output */
- int output_fr; /* output frequency */
- {
- double note_fr; /* note frequency (in Hz) */
- double step;
- int pitch; /* amiga pitch */
-
- /* special case: oversample of 0 means linear resampling */
- if (oversample == 0)
- oversample = 1;
- step_table[0] = 0;
- for (pitch = 1; pitch < REAL_MAX_PITCH + VIB_MAXDEPTH; pitch++)
- {
- note_fr = AMIGA_CLOCKFREQ / pitch;
- /* int_to_fix(1) is the normalizing factor */
- step = note_fr / output_fr * int_to_fix(1) / oversample;
- step_table[pitch] = (long)step;
- }
- }
-
- LOCAL void readjust_pitch()
- {
- int i;
- for (i = 0; i < allocated; i++)
- chan[i].step = step_table[chan[i].pitch];
- }
-
- void init_tables(oversample, frequency)
- int oversample, frequency;
- {
- create_step_table(oversample, frequency);
- readjust_pitch();
- }
-
-
- /* The playing mechanism itself.
- * According to the current channel automaton,
- * we resample the instruments in real time to
- * generate output.
- */
- void resample(oversample, number)
- int oversample;
- int number;
- {
- int i; /* sample counter */
- int channel; /* channel counter */
- int sampling; /* oversample counter */
- int step; /* fractional part for linear resampling */
- long value[NUMBER_SIDES];
- /* recombinations of the various data */
- struct audio_channel *ch;
-
- /* safety check: we can't have a segv there, provided
- * chan points to a valid sample.
- * For `empty' samples, what is needed is fix_length = 0
- * and rp_start = NULL
- */
-
- /* do the resampling, i.e., actually play sounds */
- /* code unfolding for special cases */
- switch(oversample)
- {
- case 0: /* linear resampling */
- for (i = 0; i < number; i++)
- {
- value[LEFT_SIDE] = value[RIGHT_SIDE] = 0;
- for (channel = 0; channel < allocated; channel++)
- {
- ch = chan + channel;
- switch(ch->mode)
- {
- case DO_NOTHING:
- break;
- case PLAY:
- /* Since we now have fix_length, we can
- * do that check with improved performance
- */
- if (ch->pointer < ch->samp->fix_length)
- {
- step = fractional_part(ch->pointer);
- value[ch->side] +=
- ( (ch->samp->start[C] * (total_step - step) +
- ch->samp->start[C+1] * step)
- * (ch->scaled_volume>>8)
- ) >> (ACCURACY-8);
- ch->pointer += ch->step;
- break;
- }
- else
- {
- ch->mode = REPLAY;
- ch->pointer -= ch->samp->fix_length;
- /* FALLTHRU */
- }
- case REPLAY:
- /* is there a replay ? */
- if (!ch->samp->rp_start)
- {
- ch->mode = DO_NOTHING;
- break;
- }
- while (ch->pointer >= ch->samp->fix_rp_length)
- ch->pointer -= ch->samp->fix_rp_length;
- step = fractional_part(ch->pointer);
- value[ch->side] +=
- ( (ch->samp->rp_start[C] * (total_step - step) +
- ch->samp->rp_start[C+1] * step)>>8
- * (ch->scaled_volume >>8)
- ) >> (ACCURACY-8);
- ch->pointer += ch->step;
- break;
- }
- }
- /* some assembly required... */
- output_samples(value[LEFT_SIDE], value[RIGHT_SIDE]);
- }
- break;
-
- case 1: /* no oversampling at all */
- for (i = 0; i < number; i++)
- {
- value[LEFT_SIDE] = value[RIGHT_SIDE] = 0;
- for (channel = 0; channel < allocated; channel++)
- {
- ch = chan + channel;
- switch(ch->mode)
- {
- case DO_NOTHING:
- break;
- case PLAY:
- /* Since we now have fix_length, we can
- * do that check with improved performance
- */
- if (ch->pointer < ch->samp->fix_length)
- {
- value[ch->side] += ch->samp->start[C] * ch->scaled_volume;
- ch->pointer += ch->step;
- break;
- }
- else
- {
- ch->mode = REPLAY;
- ch->pointer -= ch->samp->fix_length;
- /* FALLTHRU */
- }
- case REPLAY:
- /* is there a replay ? */
- if (!ch->samp->rp_start)
- {
- ch->mode = DO_NOTHING;
- break;
- }
- while (ch->pointer >= ch->samp->fix_rp_length)
- ch->pointer -= ch->samp->fix_rp_length;
- value[ch->side] += ch->samp->rp_start[C] * ch->scaled_volume;
- ch->pointer += ch->step;
- break;
- }
- }
- output_samples(value[LEFT_SIDE], value[RIGHT_SIDE]);
- }
- break;
- default: /* standard oversampling code */
- for (i = 0; i < number; i++)
- {
- value[LEFT_SIDE] = value[RIGHT_SIDE] = 0;
- for (channel = 0; channel < allocated; channel++)
- {
- for (sampling = 0; sampling < oversample; sampling++)
- {
- ch = chan + channel;
- switch(ch->mode)
- {
- case DO_NOTHING:
- break;
- case PLAY:
- /* Since we now have fix_length, we can
- * do that check with improved performance
- */
- if (ch->pointer < ch->samp->fix_length)
- {
- value[ch->side] += ch->samp->start[C] * ch->scaled_volume;
- ch->pointer += ch->step;
- break;
- }
- else
- {
- ch->mode = REPLAY;
- ch->pointer -= ch->samp->fix_length;
- /* FALLTHRU */
- }
- case REPLAY:
- /* is there a replay ? */
- if (!ch->samp->rp_start)
- {
- ch->mode = DO_NOTHING;
- break;
- }
- while (ch->pointer >= ch->samp->fix_rp_length)
- ch->pointer -= ch->samp->fix_rp_length;
- value[ch->side] += ch->samp->rp_start[C] * ch->scaled_volume;
- ch->pointer += ch->step;
- break;
- }
- }
- }
- output_samples(value[LEFT_SIDE]/oversample,
- value[RIGHT_SIDE]/oversample);
- }
- }
-
- #ifndef __NeXT__
- /* On the NeXT you may not flush your buffer that often, because the
- * collected data is not enough for continous play.
- */
- flush_buffer();
- #endif
- }
-
-
- /* setting up a given note */
-
- void play_note(au, samp, pitch)
- struct audio_channel *au;
- struct sample_info *samp;
- int pitch;
- {
- au->pointer = 0;
- au->pitch = pitch;
- au->step = step_table[pitch];
- au->samp = samp;
- au->scaled_volume = au->samp->volume_lookup[au->volume];
- au->mode = PLAY;
- }
-
- /* changing the current pitch (value
- * may be temporary, and not stored
- * in channel pitch, for instance vibratos.
- */
- void set_play_pitch(au, pitch)
- struct audio_channel *au;
- int pitch;
- {
- /* save current pitch in case we want to change
- * the step table on the run
- */
- au->pitch = pitch;
- au->step = step_table[pitch];
- }
-
- /* changing the current volume. You HAVE to get through
- * there so that it will work on EVERY machine.
- */
- void set_play_volume(au, volume)
- struct audio_channel *au;
- int volume;
- {
- au->volume = volume;
- au->scaled_volume = au->samp->volume_lookup[volume];
- }
-
- void set_play_position(au, pos)
- struct audio_channel *au;
- int pos;
- {
- au->pointer = int_to_fix(pos);
- }
-
-